local Cross = @@ui(cross)
local Class = @@lib(hump.class)
local lume = @@lib(lume)
local flux = @@lib(flux)
local Timer = @@lib(timer)

return Class {
   _name = "Actor",
   
   init = function (
	 self, x, y, 
	 image, quad, scale, speed, def, atk, 
	 friendly, passable_tiles, range)
      self.x, self.y = x, y
      self.range = range and range * 8 or 45
      self.view_range = self.range * 2
      self.image, self.quad = image, quad
      self.scale = scale or 1
      self.visible = friendly and true
      self.speed, self.def, self.atk = speed, def, atk
      self.friendly = friendly or nil
      self.direction = 0
      self.velocity = 0
      self.fire_cooldown = 3
      self.can_fire = true
      self.rot = 0
      self.fuel = 100
      self.health = 100
      self.friction = .002
      self.show = true
      self.timers = {}
      if self.speed then
	 self.passable_tiles = passable_tiles
	 self.path = _src("path")(self.passable_tiles)
	 self.can_move = true
      end
      Timer.every(.5, 
		  function ()
		     self:think()
      end):group(self.timers)
   end,

   update = function (self, dt)
      flux.update(dt)
      Timer.update(dt, self.timers)
      self.thinking = nil
      if self.health <= 0 then lume.remove(Game.actors, self) end
   end,
   
   draw = function (self)
      if not self.visible then return end
      if self.is_moving then
	 local tx, ty = self.move_pos[1], self.move_pos[2]
	 Game.current_screen:draw({Cross(tx, ty, 8, 8), self.path})
      end
      if not self.image then return end
      if self.friendly then $LG.setColor(1, 1, 1)
      else $LG.setColor(1, 0, 0) end
      $LG.setLineWidth(.1)
      $LG.draw(self.image, self.quad, self.x, self.y, self.rot, self.scale, self.scale)
      $LG.rectangle('line', self.x, self.y, 8, 8)
      $LG.print(self.health, self.x, self.y-4, 0, .2, .2)
      if self.fire_target then
	 $LG.setColor(1, 0, 0)
	 $LG.line(self.x+4, self.y+4, self.fire_target[1]+4, self.fire_target[2]+4)
      end
      if self:is_hovered() and _lk.isDown("c") then 
	 $LG.setColor(.5, .5, .5)
	 $LG.circle('line', self.x+4, self.y+4, self.range)
	 $LG.setColor(.1, .1, .1)
	 $LG.circle('line', self.x+4, self.y+4, self.view_range)
      end
   end,
   
   is_hovered = function (self)
      local cx, cy = Game.cursor:get_position()
      if self.x == cx and self.y == cy then return true end
   end,
   
   request_path = function (self, x, y)
      return self.path:get_path_to(self.x, self.y, x, y)
   end,
   
   goto = function (self, x, y)
      self:request_path (x, y)
   end,
   
   tile_distance = function (self, x, y)
      return Game.grid:snap(lume.distance(self.x, self.y, x, y)/8)
   end,
   
   goto_near = function (self, x, y)
      local path = self:request_path (x, y)
      local tx, ty = path[2].x, path[2].y
      self.move_pos = {tx, ty}
   end,
   
   goto_atk_range = function (self, x, y)
      local path = self:request_path (self.x, self.y, x, y)
      local point = lume.match(path,
			       function (p)
				  return lume.distance(self.x, self.y, p.x *8, p.y*8) < self.range
      end)
   end,
   
   has_in_range = function (self, x, y)
      return lume.distance(self.x, self.y, x, y) <= self.range
   end,
   
   has_in_view = function (self, x, y)
      return lume.distance(self.x, self.y, x, y) <= self.view_range
   end,
   
   pick_target = function (self, x, y)
      self.fire_target = {x, y}
   end,
   
   fire_at = function (self, x, y)
      local a = Game:actor_on_position (x, y)
      if not a then return end
      self.can_fire = nil
      self.is_firing = true
      local result = lume.weightedchoice({["miss"] = 20, ["hit"] = 80}) 
      Timer.after(self.fire_cooldown, function () self.can_fire = true end):group(self.timers)
      if result == "hit" then
	 a.health = a.health - 8
      end
   end,
   
   think = function (self)
      self.thinking = true
      self.fire_target = nil
      lume.each(Game.actors,
		function (a)
		   if not a.visible then return end
		   if a == self or a.friendly and self.friendly or not a.friendly and not self.friendly then return end
		   if self:has_in_range(a.x, a.y) then
		      if not self.fire_target or lume.distance(self.x, self.y, a.x, a.y) < lume.distance(self.x, self.y, self.fire_target[1], self.fire_target[2]) then
			 self:pick_target (a.x, a.y)
		      end
		      if self.can_fire then self:fire_at(a.x, a.y) end
		   end
      end)
      if self.friendly then
	 lume.each(Game.actors,
		   function (a)
		      if a == self or a.friendly then return end
		      if self:has_in_view(a.x, a.y) then
			 a.visible = true
		      end
	 end)
      end
      local x, y = self.path:next_point ()
      if x and y and self.can_move then
	 self:move(x, y)
      end
   end,
   
   move = function (self, x, y)
      if x and y and self.can_move then
	 flux.to(self, self.speed, {x = x*8, y = y*8})
	    :oncomplete(function ()
		  self.can_move = true
		  self.path:advance ()
		       end)
	 self.can_move = false
      end
   end,

}
